﻿// SKNotes - a note taking and gathering tool
// Copyright (C) 2009  Stefan Kueng
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace SKNotes.Utilities
{
	class Win32
	{
		public const uint SHGFI_DISPLAYNAME = 0x00000200;
		public const uint SHGFI_TYPENAME = 0x400;
		public const uint SHGFI_ICON = 0x100;
		public const uint SHGFI_LARGEICON = 0x0; // 'Large icon
		public const uint SHGFI_SMALLICON = 0x1; // 'Small icon

		[DllImport( "shell32.dll" )]
		public static extern IntPtr SHGetFileInfo( string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags );
	}

	[StructLayout( LayoutKind.Sequential )]
	public struct SHFILEINFO
	{
		public IntPtr hIcon;
		public IntPtr iIcon;
		[CLSCompliantAttribute( false )]
		public uint dwAttributes;
		[MarshalAs( UnmanagedType.ByValTStr, SizeConst = 260 )]
		public string szDisplayName;
		[MarshalAs( UnmanagedType.ByValTStr, SizeConst = 80 )]
		public string szTypeName;
	}

	[ValueConversion( typeof( string ), typeof( ImageSource ) )]
	public class FilenameIconImageConverter : IValueConverter
	{
		private static System.Collections.Generic.Dictionary<string, ImageSource> _internalCache;

		public bool Use32PixelIcon { get; set; }

		#region IValueConverter Members
		public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
		{
			ImageSource source = null;
			lock ( this )
			{
				if ( _internalCache == null )
					_internalCache = new System.Collections.Generic.Dictionary<string, ImageSource>( );

                if (value == null)
                    return source;

				string ext = Path.GetExtension( value.ToString( ) );
				if ( _internalCache.ContainsKey( ext + ( Use32PixelIcon ? "32" : "16" ) ) )
				{
					return _internalCache[ext + ( Use32PixelIcon ? "32" : "16" )];
				}
				else
				{
					string resourcePath = Path.Combine( Path.GetTempPath( ), "file" + ext );
					FileInfo resource = new FileInfo( resourcePath );
					try
					{
						if ( !resource.Exists )
						{
							using ( StreamWriter strm = resource.CreateText( ) )
								strm.Close( );
						}

						SHFILEINFO shinfo = new SHFILEINFO( );
						if ( Use32PixelIcon )
							Win32.SHGetFileInfo( resource.FullName, 0, ref shinfo, (uint)Marshal.SizeOf( shinfo ), Win32.SHGFI_ICON | Win32.SHGFI_LARGEICON );
						else
							Win32.SHGetFileInfo( resource.FullName, 0, ref shinfo, (uint)Marshal.SizeOf( shinfo ), Win32.SHGFI_ICON | Win32.SHGFI_SMALLICON );

						Icon fileIcon = Icon.FromHandle( shinfo.hIcon );
						using ( MemoryStream memStream = new MemoryStream( ) )
						{
							Bitmap iconBitmap = fileIcon.ToBitmap( );
							iconBitmap.Save( memStream, ImageFormat.Png );

							memStream.Seek( 0, SeekOrigin.Begin );
							PngBitmapDecoder bitmapDecoder = new PngBitmapDecoder( memStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad );
							source = bitmapDecoder.Frames[0];
							source.Freeze( );
						}
					}
					finally
					{
						resource.Delete( );
					}

					if ( source != null )
						_internalCache.Add( ext + ( Use32PixelIcon ? "32" : "16" ), source );
				}
			}
			return source;
		}
		public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
		{
			throw new NotImplementedException( );
		}
		#endregion
	}
}
